-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at:
--         http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local class = require 'mc.class'
local bios_enum = require 'domain.bios_firmware.defs'
local log = require 'mc.logging'
local bios_factory = require 'factory.bios_factory'
local obj_def = require 'macros.object_def'

local UpgradeConfigBuilder = class()

local PERIOD3_MHZ<const> = 15
local HPC_DEFAULT_MHZ<const> = 10
local BIOS_FILE_LEN<const> = 16 * 1024 * 1024
local BIOS_FILE_LEN_KUNPENGB<const> = 1024 * 1024
local KRUN_FILE_LEN<const> = 64 * 1024 * 1024

function UpgradeConfigBuilder:ctor(upgrade_info, package_info)
    self.config = {}
    self.config[bios_enum.UpgradePhrase.Before] = {}
    self.config[bios_enum.UpgradePhrase.Process] = {}
    self.config[bios_enum.UpgradePhrase.After] = {}
    self.upgrade_info = upgrade_info
    self.package_info = package_info
end

function UpgradeConfigBuilder:build_before_config(config_name, val)
    self.config[bios_enum.UpgradePhrase.Before][config_name] = val
end

function UpgradeConfigBuilder:build_process_config(config_name, val)
    self.config[bios_enum.UpgradePhrase.Process][config_name] = val
end

function UpgradeConfigBuilder:build_after_config(config_name, val)
    self.config[bios_enum.UpgradePhrase.After][config_name] = val
end

function UpgradeConfigBuilder:build()
    self:build_with_upgrade_mode()
    self:build_with_package_period()
    self:build_with_package_type()
    return self.config
end

function UpgradeConfigBuilder:build_force_mode()
    self:build_process_config(bios_enum.UpgradeSteps.ForcePower, {})
end

function UpgradeConfigBuilder:build_non_force_mode()
    self:build_process_config(bios_enum.UpgradeSteps.Cache, {})
end

function UpgradeConfigBuilder:build_force_power_config(mode)
    if mode == bios_enum.UpgradeMode.Force then
        self:build_force_mode()
    else
        self:build_non_force_mode()
    end
end

function UpgradeConfigBuilder:build_activate_config(mode)
    if mode == bios_enum.UpgradeMode.Hot then
        self:build_after_config(bios_enum.UpgradeSteps.ActivateFirmware,
            {ActivateBitmap = self.upgrade_info.activate_bitmap})
    end
end

function UpgradeConfigBuilder:build_component_filter(mode)
    local period = self.package_info.period
    if mode == bios_enum.UpgradeMode.Hot and period == bios_enum.PackagePeriod.Period3 then
        self:build_process_config(bios_enum.UpgradeSteps.ComponentFilter,
            {UpgradeComponents = self.upgrade_info.firmware_id_list})
    end
end

function UpgradeConfigBuilder:build_wait_component_upgrade(mode)
    local period = self.package_info.period
    if mode == bios_enum.UpgradeMode.Hot and period == bios_enum.PackagePeriod.Period3 then
        self:build_process_config(bios_enum.UpgradeSteps.WaitUpgradeFinish, {})
    end
end

function UpgradeConfigBuilder:build_with_upgrade_mode()
    self:build_process_config(bios_enum.UpgradeSteps.LockPower, {})
    local mode = self.upgrade_info.upgrade_mode
    self:build_force_power_config(mode)
    self:build_component_filter(mode)
    self:build_wait_component_upgrade(mode)
    self:build_activate_config(mode)
end

function UpgradeConfigBuilder:get_spi_rate()
    if not self.upgrade_info.spi_rate or self.upgrade_info.spi_rate == 0 then
        return PERIOD3_MHZ
    end
    return self.upgrade_info.spi_rate
end

function UpgradeConfigBuilder:build_spi_driver(period)
    if self.package_info.package_type == bios_enum.PackageType.Krun then
        return
    end
    self:build_process_config(bios_enum.UpgradeSteps.SpiDriver, {})
    if period == bios_enum.PackagePeriod.Period3 then
        local rate = self:get_spi_rate()
        log:notice('[bios]spi rate is %s', rate)
        self:build_process_config(bios_enum.UpgradeSteps.SpiDriver, {mhz = rate})
    end
end

function UpgradeConfigBuilder:build_parser_bin(period)
    self:build_process_config(bios_enum.UpgradeSteps.ParserBin, {period = period})
end

function UpgradeConfigBuilder:build_package_size(period)
    if self.package_info.package_type == bios_enum.PackageType.Krun then
        self:build_process_config(bios_enum.UpgradeSteps.UpgradeComponent, {PackageSize = KRUN_FILE_LEN})
        return
    end
    local bios_ser = bios_factory.get_service('bios_service')
    local system_id = self.upgrade_info.system_id
    local flash_size = bios_ser:get_prop(obj_def.FLASH_SIZE, system_id)
    local size = (period == bios_enum.PackagePeriod.Period3) and flash_size * BIOS_FILE_LEN_KUNPENGB or BIOS_FILE_LEN
    self:build_process_config(bios_enum.UpgradeSteps.UpgradeComponent, {PackageSize = size})
end

function UpgradeConfigBuilder:build_with_package_period()
    local period = self.package_info.period
    self:build_spi_driver(period)
    self:build_parser_bin(period)
    self:build_package_size(period)
    self:build_remove_spi_driver(period)
end

function UpgradeConfigBuilder:build_cache(package_type)
    if package_type == bios_enum.PackageType.Patch or
        (self.upgrade_info.multihost and
        self.package_info.period == bios_enum.PackagePeriod.Period3 and self.upgrade_info.startup_finished) then
        -- 补丁包及multihost post end升级，不走生效流程，因此无需缓存
        self:build_process_config(bios_enum.UpgradeSteps.Cache, nil)
    end
end

function UpgradeConfigBuilder:build_remove_spi_driver(period)
    if period == bios_enum.PackagePeriod.Period3 and
        self.upgrade_info.upgrade_mode == bios_enum.UpgradeMode.Hot then
        self:build_process_config(bios_enum.UpgradeSteps.SpiDriver, nil)
        self:build_process_config(bios_enum.UpgradeSteps.LockPower, nil)
    end
end

function UpgradeConfigBuilder:build_with_package_type()
    local package_type = self.package_info.package_type
    self:build_cache(package_type)
end

return UpgradeConfigBuilder